<?php 

if(!isset($base)) {
   $base = "./";
}

require $base . 'class/WeChat/CurlHttp.php';
require_once $base . "class/WeChat/XMLUtility.php";

class WeChatService {
	private $session;
	private $token = "";
	private $shmid;
	
	function __construct() {
		$this->session = new CurlHttp();
		
		$this->token = $this->getToken();
		if(empty($this->token)) {
			msg("TOKEN is not pre-configure");
			if(is_null($this->refreshToken()))
			    die("Can't refresh token");
		} else {
			msg("Read token from file");
		}
	}
	
	private function refreshToken() {
		msg("refresh token");

		if(file_exists(TOKEN_FILE)) {
			$fid = fopen(TOKEN_FILE, "r+");
		} else {
			$fid = fopen(TOKEN_FILE, "a+");
		}
		if($fid === false) {
			msg("Can't open token file");
			return NULL;
		}
		
		if(fseek($fid,0) !== 0) {
			msg("Can't change postion in token file to read token");
			return NULL;
		}
		
		$oldToken = fgets($fid, 4096);
		if(!flock($fid, LOCK_EX)) {
			msg("Can't lock token file");
			return NULL;
		}
		
		$is_error = false;
		$token = "";
		if(fseek($fid,0) === 0) {
			$newToken = fgets($fid, 4096);
			if($newToken === $oldToken) {
				$token = $this->login();
				if(!empty($token)) {
					if(fseek($fid,0) === 0) {
						fwrite($fid, $token);
						$this->token = $token;
					} else {
						msg("Can't change file pointer to write token");
						$is_error = true;
					}
				} else {
					msg("Can't get token from wechat service");
					$is_error = true;
				}
			}
		} else {
			msg("Can't change file point to re-read token");
			$is_error = true;
		}
		
		fclose($fid);
		
		return $is_error ? NULL : $token;
	}
	
	private function getToken() {
		if(!file_exists(TOKEN_FILE))
			return NULL;
		
		$fid = fopen(TOKEN_FILE, "r");
		if($fid === false)
			return NULL;
		
		if(!flock($fid, LOCK_SH))
			return NULL;
		
		$token = fgets($fid, 4096);
		
		fclose($fid);
		return $token;
	}
	
	private function login() {
		msg("get access token");
		$url = PROTOCOL ."://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&";
		$this->session->singleInit();
		$getField = "appid=" . APPID . "&secret=" . SECERITYID;
		$response = $this->session->get($url . $getField);
		msg("response is " . $response);
		$result = json_decode($response, 1);
		return empty($result['errcode']) ? $result['access_token'] : NULL;
	}
	
	public function getUserInfo($openId) {
		msg("get user info " . $openId);
		$url = PROTOCOL ."://api.weixin.qq.com/cgi-bin/user/info?";
		$this->session->singleInit();
		$getField = "access_token=" . $this->token . "&openid=" . $openId . "&lang=zh_CN";
		
		$response = $this->session->get($url . $getField);
		msg("response is " . $response);
		$result = json_decode($response, 1);
		if(!empty($result['errcode'])) {
			if($result['errcode'] == 42001 || $result['errcode'] == 40001) {
				msg("token expired");
				$this->refreshToken();
				$url = PROTOCOL ."://api.weixin.qq.com/cgi-bin/user/info?";
				$getField = "access_token=" . $this->token . "&openid=" . $openId . "&lang=zh_CN";
				$response = $this->session->get($url . $getField);
		        msg("response again is " . $response);
		        $result = json_decode($response, 1);
			}
		}
		return empty($result['errcode']) ? $result : NULL;
	}
	
	public function replyUser($openId, $message, $user = "") {
		msg("reply user " . $openId);
		$url = PROTOCOL ."://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" . $this->token;
		$this->session->singleInit();
		
		if(preg_match('/\[img\].*MediaId=(.*?)&msgtype=image.*\[\/img\]/', $message, $matches)) {
			msg("Image message " . $matches[1]);
			$data = $this->replyImage($openId, $matches[1]);
			
		} else if(preg_match('/\[url.*MediaId=(.*?)&format.*msgtype=voice.*\].*\[\/url\]/', $message, $matches)) {
			msg("Voice message " . $matches[1]);
			$data = $this->replyVoice($openId, $matches[1]);
			
		} else {
			msg("Text message");
			$data = $this->replyText($openId, $message);
		}
		
		msg("data is " . $data);
		$response = $this->session->post($url, $data);
		msg("response is " . $response);
		$result = json_decode($response, 1);
		if(!empty($result['errcode'])) {
			if($result['errcode'] == 42001 || $result['errcode'] == 40001) {
				msg("token expired");
				$this->refreshToken();
				$url = PROTOCOL ."://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" . $this->token;
				$response = $this->session->post($url, $data);
			    msg("response again is " . $response);
			}
		}
	}
	
	private function replyText($openId, $message) {
		$postField = array(
				"touser" => $openId,
				"msgtype" => "text",
				"text" => array("content" => "_MESSAGE_")
		);
		$data = json_encode($postField);
		$message = str_replace('\\', '\\\\', $message);
		$message = str_replace('"', '\"', $message);
		$message = "$message\n\n如果解决了您的问题，请在菜单“我的/评价”中给个评分\n若您还需要进一步回答，请继续输入您的问题";
		return str_replace("_MESSAGE_", $message, $data);
	}
	
	private function replyImage($openId, $media_ID) {
		$postField = array(
				"touser" => $openId,
				"msgtype" => "image",
				"image" => array("media_id" => $media_ID)
		);
		return json_encode($postField);
	}
	
	private function replyVoice($openId, $media_ID) {
		$postField = array(
				"touser" => $openId,
				"msgtype" => "voice",
				"voice" => array("media_id" => $media_ID)
		);
		return json_encode($postField);		
	}
	
	public function downloadMedia($mediaId, $file) {
		msg("Start download media $mediaId to $file");
		$url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" . $this->token . "&media_id=$mediaId";
		msg("url is $url");
		if($this->session->downloadFile($file, $url)) {
			return true;
		} else {
			if(file_exists($file)) {
				msg("check message");
				$fp = fopen($file, 'r');
				$response = fgets($fp, 4096);
				fclose($fp);
				if($response) {
					$result = json_decode($response, 1);
					if(!empty($result['errcode'])) {
						if($result['errcode'] == 42001 || $result['errcode'] == 40001) {
							msg("token expired");
							$this->refreshToken();
							$url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" . $this->token . "&media_id=$mediaId";
							if($this->session->downloadFile($file, $url)) {
							    return true;
							}
						}
					}
				}
				unlink($file);
			}		
		}
		return false;
	}
}

?>